package org.peoplesearch.vk.processor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Queue;
import java.util.concurrent.*;


class CredentialExecutor implements Comparable<CredentialExecutor> {

    private Credentials.VKAuthCredential credential;
    private static int REQ_PER_SECOND = 3;
    static Logger logger = LoggerFactory.getLogger(CredentialExecutor.class);

    ScheduledExecutorService executor;
    final BlockingQueue<VkCommandCounting> queue = new LinkedBlockingQueue<VkCommandCounting>();


    public CredentialExecutor(Credentials.VKAuthCredential credential) {
        this.credential = credential;
        executorInitialization();
    }

    private void executorInitialization() {
        executor = Executors.newScheduledThreadPool(REQ_PER_SECOND);
        for (int i = 0; i < REQ_PER_SECOND; i++) {
            executor.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {

                    Logger logger = LoggerFactory.getLogger("scheduledExecutor");
                    VkCommandCounting command = null;
                    synchronized (queue) {
                        if (queue.size() > 0) {
                            logger.trace("started polling");
                            command = queue.poll();
                            logger.trace("executed");
                        }
                    }
                    if (command != null)
                        command.run();

                }
            }, 0, 1, TimeUnit.SECONDS);
        }
    }

    public boolean terminate(int sec) {
        ExecutorService terminator = Executors.newSingleThreadExecutor();

        Future future = terminator.submit(new Runnable() {
            @Override
            public void run() {
                CredentialExecutor.this.waitForCompletion();
            }
        });

        try {
            boolean rezult = true;
            try {
                future.get(sec, TimeUnit.SECONDS);
                //Thread.sleep(2000);
            } catch (TimeoutException e) {
                rezult = false;
            }
            terminator.shutdownNow();
            executor.shutdownNow();
            return rezult;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    public void addTask(VkCommand command) {
        command.init(credential);
        try {
            queue.add(new VkCommandCounting(command, 0, queue));
        } catch (IllegalStateException e) {
            throw new RuntimeException(e);
        }
    }

    public int getAverageTasksToBeExecuted() {
        return queue.size();
    }

    public final void waitForCompletion() {

        try {
            synchronized (queue) {
                while (queue.size() > 0) {
                    queue.wait();
                }
            }
            executor.shutdown();
            executor.awaitTermination(10, TimeUnit.SECONDS);
            executorInitialization();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public int compareTo(CredentialExecutor other) {
        return this.getAverageTasksToBeExecuted() > other.getAverageTasksToBeExecuted() ? 1 : -1;
    }

}
